package com.leyou.auth.service;

import com.leyou.auth.config.JwtProperties;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.client.UserClient;
import com.leyou.user.entity.UserDTO;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class AuthService {

    @Autowired
    private UserClient userClient;

    @Autowired
    private JwtProperties prop;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String USER_ROLE = "ROLE_ADMIN";

    public void login(String username, String password, HttpServletResponse response) {
        try {
            //验证用户名和密码
            UserDTO userDTO = userClient.findByUsernameAndPassword(username, password);
            if(userDTO==null){
                throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
            }
            //生成token
            UserInfo userInfo = new UserInfo(userDTO.getId(), userDTO.getUsername(), USER_ROLE);
            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, prop.getPrivateKey(), prop.getUser().getExpire());
            //写入Cookie中
            new CookieUtils.CookieBuilder()
                    .name(prop.getUser().getCookieName())
                    .response(response)
                    .value(token)
                    .httpOnly(true)
                    .domain(prop.getUser().getCookieDomain())
                    .build();
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
    }

    public UserInfo verify(HttpServletRequest request, HttpServletResponse response) {
        try {
            //从Cookie中获取token
            String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());
            //验证token是否正确，超过过期时间就报错了
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
            //得到当前token的id
            String tokenId = payload.getId();
            //查看当前token是否在黑名单
            Boolean isBlack = redisTemplate.hasKey(tokenId);
            if(isBlack!=null && isBlack){
                throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
            }
            //获取UserInfo信息
            UserInfo userInfo = payload.getUserInfo();
            //查看过期时间
            Date expirationDate = payload.getExpiration();                //所以当续约的时候是不可能超过过期时间的,如果超过过期时间,在之前就已经报错了
            //在过期时间前设置一个续约token的时间
            DateTime remainTime = new DateTime(expirationDate.getTime()).minusMinutes(15);
            //续约:当续约时间在当前时间之前的时候就要续约了
            if(remainTime.isBefore(System.currentTimeMillis())){
                //生成token
                String reMainToken = JwtUtils.generateTokenExpireInMinutes(userInfo, prop.getPrivateKey(), prop.getUser().getExpire());
                //写入Cookie中
                new CookieUtils.CookieBuilder()
                        .name(prop.getUser().getCookieName())
                        .response(response)
                        .value(reMainToken)
                        .httpOnly(true)
                        .domain(prop.getUser().getCookieDomain())
                        .build();
            }
            return userInfo;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }

    }

    public void logout(String token, HttpServletResponse response) {
        try {
            //校验token是否正确，如果不正确，就不用做了
            Payload<Object> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey());
            //得到token的id
            String tokenId = payload.getId();
            //得到token剩余有效时间
            long remainTime = payload.getExpiration().getTime() - System.currentTimeMillis();
            //如果剩余时间还有两秒以上，存入redis黑名单
            if(remainTime>2000){
                redisTemplate.opsForValue().set(tokenId, "1", remainTime, TimeUnit.MILLISECONDS);
            }
            //删除token
            CookieUtils.deleteCookie(prop.getUser().getCookieName(), prop.getUser().getCookieDomain(), response);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.TOKEN_ERROR);
        }

    }




}
